package com.hicorp.segment.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hicorp.segment.pojo.GlobalOption;
import com.hicorp.segment.pojo.GlobalSetting;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class BaseSqlOption {

    private static final String UPPER_CAMEL = "upperCamel";
    private static final String LOWER_CAMEL = "lowerCamel";

    /**
     * 短横线转驼峰
     *
     * @param s         短横线命名的字符串
     * @param camelType true 大驼峰, false 小驼峰
     * @return 驼峰命名的字符串
     */
    public static String setKebab2Camel(String s, String camelType) {
        // 1. 非空处理
        if (s == null || "".equals(s.trim())) {
            return "";
        }
        StringBuilder sb = new StringBuilder(s);
        if (camelType.equals("upperCamel")) {
            sb.replace(0, 1, sb.substring(0, 1).toUpperCase());
        } else if (camelType.equals("lowerCamel")) {
            sb.replace(0, 1, sb.substring(0, 1).toLowerCase());
        } else {
            throw new IllegalArgumentException("输入的参数错误,无法完成转换");
        }
        Matcher mc = Pattern.compile("-").matcher(s);
        int i = 0;
        while (mc.find()) {
            int position = mc.end() - (i++);
            sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 查询所有
     *
     * @param tableName 数据库表名
     * @return 查询到的List表单
     */
    public List<?> selectAll(String tableName)
            throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        String mapperClassName = setKebab2Camel(tableName, UPPER_CAMEL) + GlobalSetting.MAPPER_SUFFIX_NAME;
        String mapperClassPackageName = GlobalSetting.PACKAGE_NAME + "." + GlobalSetting.MAPPER_NAME + "." + mapperClassName;
        Class<?> clazz = Class.forName(mapperClassPackageName);
        String mapperName = setKebab2Camel(tableName, LOWER_CAMEL) + GlobalSetting.MAPPER_SUFFIX_NAME;
        Object mapper = SpringUtil.getBean(mapperName);
        Method method = clazz.getMethod("selectAll");
        Object result = method.invoke(mapper);
        if (result instanceof ArrayList<?>) {
            return (List<?>) result;
        } else {
            throw new IllegalAccessException("查询结果不是一个List!");
        }
    }

    /**
     * 单条数据的变更
     *
     * @param tableName 表名
     * @param record    数据内容
     * @param operation 操作类型(新增/编辑)
     * @return 变更后的数据
     */
    public Object changeSingleRecord(String tableName, Object record, String operation) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        if (!operation.equals(GlobalOption.INSERT) && !operation.equals(GlobalOption.UPDATE)) {
            throw new IllegalArgumentException("操作类型不符!");
        }

        // 小驼峰Pojo名, 用于注入.
        String lowerCamelTableName = setKebab2Camel(tableName, LOWER_CAMEL);

        // 大驼峰Pojo名, 用于反射.
        String upperCamelTableName = setKebab2Camel(tableName, UPPER_CAMEL);

        // 小驼峰Mapper名，用于注入.
        String mapperName = lowerCamelTableName + GlobalSetting.MAPPER_SUFFIX_NAME;

        // 利用SpringUtil工具类注入Mapper.
        Object mapper = SpringUtil.getBean(mapperName);

        // Pojo类及包名, 用于反射
        String pojoClassPackageName = GlobalSetting.PACKAGE_NAME + "." + GlobalSetting.PO_NAME + "." + upperCamelTableName;
        Class<?> pojoClass = Class.forName(pojoClassPackageName);

        // Mapper类及包名, 用于反射.
        String mapperClassPackageName = GlobalSetting.PACKAGE_NAME + "." + GlobalSetting.MAPPER_NAME + "." + upperCamelTableName + GlobalSetting.MAPPER_SUFFIX_NAME;
        Class<?> mapperClass = Class.forName(mapperClassPackageName);

        // 利用反射获取方法.
        Method method = mapperClass.getMethod(operation, Object.class);

        // 将record转换成具体的pojo类型的数据.
        ObjectMapper objectMapper = new ObjectMapper();
        Object convertValue = objectMapper.convertValue(record, pojoClass);

        // 利用反射执行新增或编辑方法.
        method.invoke(mapper, convertValue);

        return convertValue;
    }

    /**
     * 批量数据的变更
     *
     * @param tableName 表名
     * @param records   数据内容
     * @param operation 操作类型(新增/编辑)
     * @return 变更后的数据
     */
    public List<?> changeBatchRecord(String tableName, List<?> records, String operation) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        if (!operation.equals(GlobalOption.INSERT_LIST) && !operation.equals(GlobalOption.UPDATE_LIST)) {
            throw new IllegalArgumentException("操作类型不符!");
        }

        // 大驼峰Pojo名, 用于反射.
        String upperCamelPojoName = setKebab2Camel(tableName, UPPER_CAMEL);
        // 子表的Class
        Class<?> pojoClass = Class.forName(GlobalSetting.PACKAGE_NAME + "." + GlobalSetting.PO_NAME + "." + upperCamelPojoName);
        // 将数据转换成具体的类型.
        List<Object> recordList = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for (Object item : records) {
            Object convertPojoValue = objectMapper.convertValue(item, pojoClass);
            recordList.add(convertPojoValue);
        }

        // 小驼峰Mapper名，用于注入.
        String lowerCamelMapperName = setKebab2Camel(tableName, LOWER_CAMEL) + GlobalSetting.MAPPER_SUFFIX_NAME;
        // 利用SpringUtil工具类注入Mapper.
        Object mapper = SpringUtil.getBean(lowerCamelMapperName);

        // 大驼峰Mapper名, 用于反射.
        String upperCamelMapperName = setKebab2Camel(tableName, UPPER_CAMEL) + GlobalSetting.MAPPER_SUFFIX_NAME;

        // Mapper类及包名, 用于反射.
        String mapperClassPackageName = GlobalSetting.PACKAGE_NAME + "." + GlobalSetting.MAPPER_NAME + "." + upperCamelMapperName;
        Class<?> mapperClass = Class.forName(mapperClassPackageName);

        // 利用反射获取方法.
        Method mapperMethod = mapperClass.getMethod(operation, List.class);
        // 执行批量新增或编辑方法.
        mapperMethod.invoke(mapper, recordList);
        return records;
    }
}
